var nfs = require("@native.fs");
var sys = require("@native.builtin");
var error = require("error.js");

var __FILE__ = "fs.js";
var ERR = new error.ThrowError(__FILE__);

var _O_RDONLY = 0x0000
var _O_WRONLY = 0x0001
var _O_RDWR = 0x0002
var _O_APPEND = 0x0008
var _O_CREAT = 0x0100
var _O_TRUNC = 0x0200
var _O_EXCL = 0x0400
var _O_TEXT = 0x4000
var _O_BINARY = 0x8000
var _O_WTEXT = 0x10000
var _O_U16TEXT = 0x20000
var _O_U8TEXT = 0x40000
var _O_ACCMODE = (_O_RDONLY|_O_WRONLY|_O_RDWR)

var _O_RAW = _O_BINARY
var _O_NOINHERIT = 0x0080
var _O_TEMPORARY = 0x0040
var _O_SHORT_LIVED = 0x1000

var _O_SEQUENTIAL = 0x0020
var _O_RANDOM = 0x0010

var O_RDONLY = _O_RDONLY
var O_WRONLY = _O_WRONLY
var O_RDWR = _O_RDWR
var O_APPEND = _O_APPEND
var O_CREAT = _O_CREAT
var O_TRUNC = _O_TRUNC
var O_EXCL = _O_EXCL
var O_TEXT = _O_TEXT
var O_BINARY = _O_BINARY
var O_RAW = _O_BINARY
var O_TEMPORARY = _O_TEMPORARY
var O_NOINHERIT = _O_NOINHERIT
var O_SEQUENTIAL = _O_SEQUENTIAL
var O_RANDOM = _O_RANDOM
var O_ACCMODE = _O_ACCMODE

var SEEK_CUR = 1
var SEEK_END = 2
var SEEK_SET = 0

function convertFlags(flag) {
    if (typeof flag == "string") {
        switch (flag) {
            case 'r': return O_RDONLY;
            case 'rs':
            // case 'sr': return O_RDONLY | O_SYNC;
            case 'sr': return O_RDONLY;
            case 'rb': return O_RDONLY | O_BINARY;


            case 'r+': return O_RDWR;
            case 'rb+': return O_RDWR | O_BINARY;
            case 'rs+':
            // case 'sr+': return O_RDWR | O_SYNC;
            case 'sr+': return O_RDWR;


            case 'w': return O_TRUNC | O_CREAT | O_WRONLY;
            case 'wb': return O_TRUNC | O_CREAT | O_WRONLY | O_BINARY;
            case 'wx':
            case 'xw': return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;

            case 'w+': return O_TRUNC | O_CREAT | O_RDWR;
            case 'wb+': return O_TRUNC | O_CREAT | O_RDWR | O_BINARY;
            case 'wx+':
            case 'xw+': return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;

            case 'a': return O_APPEND | O_CREAT | O_WRONLY;
            case 'ab': return O_APPEND | O_CREAT | O_WRONLY | O_BINARY;
            case 'ax':
            case 'xa': return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;

            case 'a+': return O_APPEND | O_CREAT | O_RDWR;
            case 'ax+':
            case 'xa+': return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
        }
    }
    ERR.trace("convertFlags", 77, "FS_FLAG_ERROR", "Bad argument: flags");
}

function size(path){
    var fd = nfs.open(path, O_RDONLY, 511);
    if(fd < 0){
        ERR.trace("size", 84, "FS_OPEN_ERROR", "FILE OPEN FAILED");
        return undefined;
    }
    var len=nfs.lseek(fd,0,SEEK_END);

    nfs.lseek(fd,0,SEEK_SET);
    nfs.close(fd);
    return len;
}

function exists(path){
    if(nfs.access(path, 0) == 0 )
        return true;
    else
        return false;
}

function rename(oldpath, newpath){
    if(nfs.rename(oldpath, newpath) >=0)
        return true;
    else 
        return false;
}

function remove(oldpath){
    if(nfs.remove(oldpath) >=0)
        return true;
    else 
        return false;
}

function readFile(path, flag){
    var pflag = convertFlags(flag);
    var len = size(path);
    if(len == 0)
        return "";

    var fd = nfs.open(path, pflag, 511);
    if(fd < 0){
        ERR.trace("readFile", 117, "FS_OPEN_ERROR", "FILE OPEN FAILED");
        return undefined;
    }
    var cp_buff = sys.malloc(len);
    if(cp_buff == null){
        nfs.close(fd);
        return undefined;
    }
    var res = nfs.read(fd, cp_buff, len);
    nfs.close(fd);

    if(flag.indexOf("b") == -1){
        var buffer = sys.toJsArray(cp_buff, len);
        sys.free(cp_buff);
        return buffer;
    }else{
        var buffer = sys.toJsString(cp_buff, len);
        sys.free(cp_buff);
        return buffer;
    }
}


function writeFile(path, buf, flag){
    var pflag = convertFlags(flag);
    var fd = nfs.open(path, pflag, 511);
    if(fd < 0){
        ERR.trace("writeFile", 145, "FS_OPEN_ERROR", "FILE OPEN FAILED");
        return undefined;
    }
    var len = buf.length;
    var data = sys.malloc(len);
    if(data == null){
        ERR.trace("writeFile", 155, "NO MEM", "FILE writeFile FAILED");
        return undefined;
    }
    var ret = sys.copy(data, buf, len);
    if(ret == false){
        sys.free(data);
        ERR.trace("writeFile", 162, "NO MEM", "FILE COPY FAILED");
        return undefined;
    }

    var res = nfs.write(fd, data, len);
    nfs.close(fd);
    sys.free(data);
    if (res >= 0) return res;
    ERR.trace("writeFile", 154, "FS_WRITE_ERROR", "FILE WRITE FAILED");
    return undefined;
}

function getcwd(){
    var data = sys.malloc(128);
    if(data == null){
        ERR.trace("getcwd", 186, "NO MEM", "FILE getcwd FAILED");
        return undefined;
    }
    var res = nfs.getcwd(data, 128);
    if(res == null){
        sys.free(data);
        return undefined;
    }
    
    var buffer = sys.toJsString(data, 128);
    sys.free(data);
    return buffer;
}

function chdir(path){
    nfs.chdir(path);
}


// if (globalThis.__proto__ != undefined) {
//     module.exports = {
//         size: size,
//         exists: exists,
//         rename: rename,
//         remove: remove,
//         readFile: readFile,
//         writeFile: writeFile,
//     };
// }

